const nodemailer = require("nodemailer");
const chalk = require("chalk").default;
const beautify = require("json-beautify");
const mailparser = require("mailparser");
const fs = require("fs");
const path = require("path");
const buffer = require("buffer");
const es = require("event-stream");
/**
 * 
 * @param {{port:Number,host:String,secure:Boolean,auth:{user:String,pass:String}}} transportOptions 
 * @param {String[]} emlFiles 
 * @param {String} receivers 
 */
function SendMail(transportOptions, emlFiles, receivers) {
    let transport = nodemailer.createTransport(transportOptions);
    /**
     * 
     * @param {String} from 
     * @param {String} to 
     * @param {String} eml_file_path 
     */
    function PromisifyTransportSendmail(from, to, eml_file_path) {
        return new Promise((res, rej) => {
            let emlStream = fs.createReadStream(eml_file_path);
            // emlStream = emlStream.pipe(through2(function (chunk, enc, callback) {
            //     let text = chunk.toString();
            //     "debugger"
            //     text = emojiText.convert(text);
            //     "debugger"
            //     this.push(buffer.Buffer(text));
            //     callback();
            // }));
            mailparser.simpleParser(emlStream, (error, mail) => {
                if (error) {
                    console.error(chalk.bgRed.white(`mailparser failed to parse [${eml_file_path}]`));
                    console.error(error);
                    return transport.sendMail({
                        from: from,
                        to: receivers,
                        replyTo: from,
                        raw: {
                            path: eml_file_path
                        }
                    }, (error, info) => {
                        if (error) {
                            return rej(error);
                        }
                        res(info);
                    })
                } else {
                    let rawStream = fs.createReadStream(eml_file_path);
                    let buf = buffer.Buffer("");
                    let phase = 0;
                    let s = rawStream.pipe(es.split()).pipe(es.mapSync(
                        /**
                         * @param {String} line
                         */
                        line => {
                            s.pause();
                            if (!phase) {
                                if (line.includes("Content-Type") && line.includes("text/html")) {
                                    phase = 1; //
                                }
                            } else {
                                if (line.includes("<html")) {
                                    phase = 2;
                                    buf += line;
                                    if (line.includes("</html>")) {
                                        phase = 3;
                                    }
                                } else if (phase == 2) {
                                    buf += line;
                                    if (line.includes("</html>")) {
                                        phase = 3;
                                    }
                                }
                            }
                            s.resume();
                        }));
                    s.on("close", () => {
                        // buf
                        // debugger
                        transport.sendMail({
                            from: from,
                            to: mail.to ? mail.to.value : to,
                            attachments: mail.attachments,
                            subject: mail.subject || `[MAIL-ALL-EMLS]Subject is undefined`,
                            text: mail.text,
                            html: buf,
                            date: mail.date || new Date(),
                            // textEncoding: "base64"
                        }, (error, info) => {
                            if (error) {
                                return rej(error);
                            }
                            res(info);
                        })
                    })

                }
            })

        })
    }
    /**
     * 
     * @param {String} eml_file 
     * @param {String} from
     * @param {String} receivers 
     */
    function sendOneMail(eml_file, from, receivers) {
        let count = 0;
        let last_error_message = "";
        let g = (function* () {
            while (count < 5) {
                yield PromisifyTransportSendmail(from, receivers, eml_file);
                count++;
            }
        })();
        let it = g.next();
        return new Promise((resolve, reject) => {
            function BootStrap() {
                if (!it.done) {
                    it.value.then((info) => {
                        console.log(chalk.underline.green(`[${eml_file}]`));
                        console.log(chalk.green(beautify(info)));
                        resolve("this is ok");
                    });
                    it.value.catch((error) => {
                        last_error_message = `[${eml_file}] :${error.message}`;
                        console.error(chalk.bgRed.white(last_error_message));
                        it = g.next();
                        BootStrap();
                    })
                } else {
                    reject(last_error_message);
                }
            }
            BootStrap();
        });
    }

    function* Generator() {
        for (let eml of emlFiles) {
            yield sendOneMail(eml, transportOptions.auth.user, receivers);
        }
    }
    return new Promise((resolve, reject) => {
        let g = Generator();
        let it = g.next();
        let success_count = 0;
        let failed_messages = [];

        function BootStap() {
            if (!it.done) {
                it.value.then(() => {
                    success_count++;
                    it = g.next();
                    setTimeout(() => BootStap(), (parseInt(Math.random() * 100) % 5) * 1000);
                }).catch((error) => {
                    failed_messages.push(error);
                    it = g.next();
                    setTimeout(() => BootStap(), 10);
                })
            } else {
                resolve({
                    success_count,
                    failed_messages
                });
            }
        }
        BootStap();
    })
}

module.exports = {
    SendMail: SendMail
}